#include "system/windowsmanager.h"
#include "system/window.h"

namespace dw {
	namespace system {

//------------------------------------------------------------------------------
// Commands
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void WindowsManager::handleEvents()
{
	MSG msg;

	while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		::TranslateMessage(&msg);
		::DispatchMessage(&msg);
	}
}

//------------------------------------------------------------------------------
// Construction & destruction
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
WindowsManager::WindowsManager()
{
}

//------------------------------------------------------------------------------
WindowsManager::~WindowsManager()
{
	dwAssert(_windows.empty(), "Some windows have not been unregistered");
}

//------------------------------------------------------------------------------
// Commands
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void WindowsManager::registerWindow(Window* window)
{
	dwAssert(window != NULL, "Invalid parameter: window == NULL");
	dwAssert(std::find(_windows.begin(), _windows.end(), window) == _windows.end(), "Invalid parameter: window is already registered");

	_windows.push_back(window);
}

//------------------------------------------------------------------------------
void WindowsManager::unregisterWindow(Window* window)
{
	dwAssert(window != NULL, "Invalid parameter: window == NULL");
	dwAssert(std::find(_windows.begin(), _windows.end(), window) != _windows.end(), "Invalid parameter: window has not been registered");

	_windows.erase(std::find(_windows.begin(), _windows.end(), window));
}

//------------------------------------------------------------------------------
/*static*/ HRESULT CALLBACK WindowsManager::windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	Window* window = WindowsManager::getInstance().getWindow(hWnd);

	if (window != NULL)
	{
		switch (message)
		{
		case WM_ACTIVATE :
			{
				if (LOWORD(wParam))
					window->onActivate();
				else
					window->onDeactivate();
				return 0;
			}
		case WM_SYSCOMMAND :
			{
				switch (wParam)
				{
				case SC_SCREENSAVE:
				case SC_MONITORPOWER:
					return 0;
				}
				break ;
			}
		case WM_CLOSE :
			{
				window->onClose();
				return 0;
			}
		case WM_PAINT :
			{
				window->onPaint();
				break ;
			}
		case WM_KEYDOWN :
			{
				window->onKeyDown((int32)wParam);
				return 0;
			}
		case WM_KEYUP :
			{
				window->onKeyUp((int32)wParam);
				return 0;
			}
		case WM_CHAR :
				break ;
		case WM_MOVE :
			{
				window->onMove(LOWORD(lParam), HIWORD(lParam));
				return 0;
			}
		case WM_SIZE :
			{
				window->onSize(LOWORD(lParam), HIWORD(lParam));
				return 0;
			}
		case WM_LBUTTONDOWN :
			{
				/*
				int16 xPos = LOWORD(lParam); 
				int16 yPos = HIWORD(lParam);
				input::mouseButtonDown(xPos, yPos, MOUSE_BUTTON_LEFT);
				onMouseDown(xPos, yPos, MOUSE_BUTTON_LEFT);

				// capture the mouse, for moving windows around etc
				SetCapture(m_hWnd);
				*/

				return 0;
			}
		case WM_MOUSEMOVE :
			{
				/*
				short int xPos = LOWORD(lParam); 
				short int yPos = HIWORD(lParam);
				Vector2i lastMousePos = input::lastMousePos();
				input::mousePos(xPos, yPos);
				onMouseMove(xPos, yPos, lastMousePos.x, lastMousePos.y);
				*/

				return 0;
			}
		case WM_LBUTTONUP :
			{
				/*
				short int xPos = LOWORD(lParam); 
				short int yPos = HIWORD(lParam);
				input::mouseButtonUp(xPos, yPos, MOUSE_BUTTON_LEFT);
				onMouseUp(xPos, yPos, MOUSE_BUTTON_LEFT);

				// release capture
				ReleaseCapture();
				*/

				return 0;
			}
		}
	}
	else
	{
		dwLogDebug("Unhandled event (%d) on 0x%p\n", message, hWnd);
	}

	return ::DefWindowProc(hWnd, message, wParam, lParam);
}

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

struct WindowPredicate
{
public :
	WindowPredicate(HWND hWnd) : _hWnd(hWnd) { ; }

	bool operator () (Window* window) { return window->getHandle() == _hWnd; }

private :
	HWND _hWnd;
};

//------------------------------------------------------------------------------
Window* WindowsManager::getWindow(HWND hWnd)
{
	dwAssert(hWnd != NULL, "Invalid parameter: hWnd == NULL");

	WindowsCollection::iterator it = std::find_if(_windows.begin(), _windows.end(), WindowPredicate(hWnd));

	if (it != _windows.end())
	{
		return *it;
	}

	return NULL;
}

	} // namespace system
} // namespace dw
